﻿using Application.Cache;
using AutoMapper;
using Castle.Core.Logging;
using Domain.IRepositorys;
using Domain.Model;
using Domain.Services;
using Domain.Types;
using DTO;
using Infrastructure.Error;
using Infrastructure.UniOfWorkBase;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utility;
using static Utility.PolicyUtil;

namespace Application.App
{
    public class TaskApplication
    {
        public TaskService taskService { get; set; }
        public IEFUnitOfWork efUnitOfWork { get; set; }
        public IUserRepository userRepository { get; set; }
        public ITaskCategoryRepository taskCategoryRepository { get; set; }
        public ITaskRepository taskRepository { get; set; }
        public ITaskTakeRepository taskTakeRepository { get; set; }
        public IBlackListRepository blackListRepository { get; set; }
        public IWalletRepository walletRepository { get; set; }
        public TaskDetailsCache taskDetailsCache { get; set; }

        public ILogger<TaskApplication> Logger { get; set; }

        public TaskAggregate NewTask(int uid, NewTaskInput newTaskInput)
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<NewTaskInput, TaskAudit>();
                cfg.CreateMap<NewTaskInput, TaskAggregate>();

                cfg.SourceMemberNamingConvention = new PascalCaseNamingConvention();
                cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();
            });
            var mapper = config.CreateMapper();

            var u = userRepository.GetByKey(uid);

            taskService.CheckUserCanCreate(u);
            var category = taskCategoryRepository.GetByKey(newTaskInput.TaskCategoryID);
            taskService.CheckTaskData(category.GetNFieldData(), category.NeedSubField, newTaskInput.FieldData, newTaskInput.StepFieldData, newTaskInput.SubFieldName, newTaskInput.Price, newTaskInput.TotalCount, newTaskInput.TotalPrice);
            foreach (var item in newTaskInput.StepFieldData)
            {
                if (item.ID == Guid.Empty) item.ID = Guid.NewGuid();
            }

            TaskAggregate taskAggregate = mapper.Map<TaskAggregate>(newTaskInput);
            taskAggregate.CategoryID = newTaskInput.TaskCategoryID;
            taskAggregate.Name = newTaskInput.FieldData.FirstOrDefault()?.Text;
            taskAggregate.SetDataField(newTaskInput.FieldData);
            taskAggregate.SetStepDataField(newTaskInput.StepFieldData);
            if (!string.IsNullOrWhiteSpace(newTaskInput.SubFieldName))
            {
                taskAggregate.NeedSubField = true;
            }
            taskAggregate.FinishTime = newTaskInput.FinishTime;
            taskAggregate.FreshTime = DateTime.Now;
            taskAggregate.Price = newTaskInput.Price;
            taskAggregate.Status = TaskStatus.待发布;
            taskAggregate.RemainCount = taskAggregate.TotalCount = 0;
            taskAggregate.UserID = uid;
            taskAggregate.TaskAudits = new List<TaskAudit>();
            taskAggregate.BeFinishCount = 0;

            //taskAggregate.SubFieldName = newTaskInput.SubFieldName;
            //taskAggregate.IsFinishAll = newTaskInput.IsFinishAll;
            //taskAggregate.FinishTime = newTaskInput.FinishTime;


            taskAggregate = taskRepository.Insert(taskAggregate);

            TaskAudit taskAudit = mapper.Map<TaskAudit>(newTaskInput);

            taskAudit.AuditStatus = TaskAuditStatus.待提交;
            taskAudit.Count = newTaskInput.TotalCount;
            taskAudit.IsAdd = false;
            taskAudit.Order = 0;
            taskAudit.PayMoney = taskAudit.TotalMoney = newTaskInput.TotalCount * newTaskInput.Price;

            taskAudit.PayMoney = 1;
            taskAggregate.TaskAudits.Add(taskAudit);


            efUnitOfWork.Commit();

            return taskAggregate;
        }

        public ModifyTaskDetailsOutput GetModifyTaskDetails(int uid, int taskID)
        {
            var task = taskRepository.GetByKey(taskID);
            if (task.UserID != uid) throw new BizException("任务不是该用户所有");
            //if (task.Status != TaskStatus.待发布) throw new BizException($"'{task.Status.ToString()}'的任务无法删除！");

            var taskAudit = task.TaskAudits.LastOrDefault(i => !i.IsAdd);
            var category = taskCategoryRepository.GetByKey(task.CategoryID);

            ModifyTaskDetailsOutput modifyTaskDetailsOutput = new ModifyTaskDetailsOutput();
            modifyTaskDetailsOutput.Icon = category.Icon;
            modifyTaskDetailsOutput.CategoryID = category.ID;
            modifyTaskDetailsOutput.Title = category.Title;
            modifyTaskDetailsOutput.FieldData = task.FieldData;
            modifyTaskDetailsOutput.NeedSubField = category.NeedSubField;
            modifyTaskDetailsOutput.NeedTaskStepData = category.NeedTaskStepData;
            modifyTaskDetailsOutput.Sort = category.Sort;
            modifyTaskDetailsOutput.SubTitle = category.SubTitle;
            modifyTaskDetailsOutput.Title = category.Title;
            //modifyTaskDetailsOutput.BeFinishCount = task.BeFinishCount;
            modifyTaskDetailsOutput.ID = task.ID;
            modifyTaskDetailsOutput.IsFinishAll = taskAudit.IsFinishAll;
            modifyTaskDetailsOutput.LimitAudit = taskAudit.LimitAudit;
            modifyTaskDetailsOutput.LimitTime = taskAudit.LimitTime;
            modifyTaskDetailsOutput.Name = task.Name;
            modifyTaskDetailsOutput.Price = taskAudit.Price;
            //modifyTaskDetailsOutput.RemainCount = task.RemainCount;
            modifyTaskDetailsOutput.Status = task.Status;
            modifyTaskDetailsOutput.StepFieldData = task.StepFieldData;
            modifyTaskDetailsOutput.SubFieldName = task.SubFieldName;
            modifyTaskDetailsOutput.TotalCount = taskAudit.Count;
            modifyTaskDetailsOutput.UserID = task.UserID;
            modifyTaskDetailsOutput.TaskAuditID = taskAudit.ID;
            modifyTaskDetailsOutput.FinishTime = task.FinishTime;

            return modifyTaskDetailsOutput;
        }

        public TaskAggregate ModifyTask(int uid, ModifyTaskInput modifyTaskInput)
        {
            if (modifyTaskInput.ID <= 0) throw new BizException("任务标示不正确，无法找到要修改的任务！");

            var u = userRepository.GetByKey(uid);

            TaskAggregate taskAggregate = taskRepository.GetByKey(modifyTaskInput.ID);

            if (taskAggregate.UserID != uid) throw new BizException("任务不是该用户所有");

            TaskAudit taskAudit = taskAggregate.TaskAudits.FirstOrDefault(i => i.ID == modifyTaskInput.TaskAuditID);

            if (taskAudit.AuditStatus == TaskAuditStatus.审核通过) throw new BizException("无法修改审核通过的任务！");
            if (taskAudit == null) throw new BizException("任务标示不正确，无法找到要修改的任务！");
            if (taskAudit.IsAdd) throw new BizException("无法要修改追加的任务！");

            taskService.CheckTaskData(taskAggregate.GetDataField(), taskAggregate.NeedSubField, modifyTaskInput.FieldData, modifyTaskInput.StepFieldData, modifyTaskInput.SubFieldName, modifyTaskInput.Price, modifyTaskInput.TotalCount, modifyTaskInput.TotalPrice);
            foreach (var item in modifyTaskInput.StepFieldData)
            {
                if (item.ID == Guid.Empty) item.ID = Guid.NewGuid();
            }



            if (taskAggregate.Status != TaskStatus.待发布) throw new BizException("无法修改发布过的任务！");

            taskAggregate.CategoryID = modifyTaskInput.TaskCategoryID;
            taskAggregate.SetDataField(modifyTaskInput.FieldData);
            taskAggregate.FinishTime = modifyTaskInput.FinishTime;
            taskAggregate.IsFinishAll = modifyTaskInput.IsFinishAll;
            taskAggregate.LimitAudit = modifyTaskInput.LimitAudit;
            taskAggregate.LimitTime = modifyTaskInput.LimitTime;
            taskAggregate.Name = modifyTaskInput.FieldData.FirstOrDefault()?.Text;
            taskAggregate.SetStepDataField(modifyTaskInput.StepFieldData);
            if (!string.IsNullOrWhiteSpace(taskAggregate.SubFieldName))
            {
                taskAggregate.NeedSubField = true;
            }
            taskAggregate.SubFieldName = modifyTaskInput.SubFieldName;
            taskAggregate.FreshTime = DateTime.Now;
            taskAggregate.Price = modifyTaskInput.Price;
            taskAggregate.Status = TaskStatus.待发布;

            taskRepository.Update(taskAggregate);



            taskAudit.AuditStatus = TaskAuditStatus.待提交;
            taskAudit.Count = modifyTaskInput.TotalCount;
            taskAudit.FinishTime = modifyTaskInput.FinishTime;
            taskAudit.IsFinishAll = modifyTaskInput.IsFinishAll;
            taskAudit.LimitAudit = modifyTaskInput.LimitAudit;
            //重置支付状态
            taskAudit.IsPay = false;
            taskAudit.LimitTime = modifyTaskInput.LimitTime;
            taskAudit.Price = modifyTaskInput.Price;
            taskAudit.PayMoney = taskAudit.TotalMoney = modifyTaskInput.TotalCount * modifyTaskInput.Price;

            taskAudit.PayMoney = 1;

            taskService.TaskLog(taskAggregate.ID, uid, TaskLogType.任务修改, null, "任务修改", taskAudit.ID);

            efUnitOfWork.Commit();

            return taskAggregate;
        }


        public int GetPayTaskChargeFee(int uid, int TaskID, int TaskAuditID)
        {
            var task = taskRepository.GetByKey(TaskID);
            var needPayFee = taskService.GetPayTaskChargeFee(uid, task, TaskAuditID);

            return needPayFee;
        }

        public bool PayTask(int uid, int taskID, int taskAuditID)
        {
            try
            {
                var r = taskService.PayTask(uid, taskID, taskAuditID);
                return r;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public TaskTakeAggregate TakeTask(int uid, int taskID)
        {
            taskService.CheckUserCanTakeTask(uid, taskID);

            TaskTakeAggregate r = null;
            try
            {
                r = PolicyUtil.WaitAndRetry(new[] { 1, 2, 3 }, () =>
                {
                    return taskService.TakeTask(uid, taskID);
                });

                return r;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 提交数据审核任务
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="submitTakeTaskInput"></param>
        /// <returns></returns>
        public bool SubmitTakeTask(int uid, SubmitTakeTaskDataDto submitTakeTaskInput)
        {
            var taketask = taskTakeRepository.GetByKey(submitTakeTaskInput.TaskTakeID);
            if (taketask.Status!=TaskTakeAuditStatus.待提交&& taketask.Status != TaskTakeAuditStatus.审核拒绝) throw new BizException("当前任务状态不能进行操作");

            var task = taskRepository.GetByKey(taketask.TaskID);

            var jtlist = task.GetStepDataField().Where(i => i.Type == TaskStepFieldType.收集截图);
            foreach (var item in jtlist)
            {
                var f = submitTakeTaskInput.StepFieldData.FirstOrDefault(i=>i.ID==item.ID);

                Dictionary<string, string> map = new Dictionary<string, string>();

                if (f == null) throw new BizException("收集截图未提交",dic=> {
                    dic.Add("id", item.ID);
                });
                if (string.IsNullOrWhiteSpace(f.PicUrl)) throw new BizException("收集截图未提交", dic => {
                    dic.Add("id", item.ID);
                });
                //if (string.IsNullOrWhiteSpace(f.Text)) throw new BizException("收集截图文字未输入", dic => {
                //    dic.Add("id", item.ID);
                //});
            }
            if (task.NeedSubField && string.IsNullOrWhiteSpace(submitTakeTaskInput.SubFieldValue)) throw new BizException("提交数据不能为空");


            if (taketask.UserID != uid) throw new BizException("任务不是该用户所有");
            if (taketask.Status == TaskTakeAuditStatus.待审核) throw new BizException("任务已提交审核");
            if (taketask.Status == TaskTakeAuditStatus.审核通过) throw new BizException("你领取的任务已完成");

            taketask.Status = TaskTakeAuditStatus.待审核;
            taketask.AuditOutTime = DateTime.Now.AddHours((int)taketask.TakeLimitAudit);
            taketask.StatusInfo = "提交审核";
            taketask.UT = DateTime.Now;
            taketask.FromData = submitTakeTaskInput.GetJsonData();

            efUnitOfWork.Commit();
            return false;
        }
        /// <summary>
        /// 领取任务审核通过
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="submitTakeTaskInput"></param>
        /// <returns></returns>
        public bool TakeTaskAudit(int uid, TakeTaskAuditPassInput taskAuditPassInput)
        {
            if (taskAuditPassInput.AuditStatus == TaskTakeAuditStatus.审核通过)
            {
                try
                {
                    var r = PolicyUtil.WaitAndRetry<bool>(new int[] { 1, 2, 2 }, () =>
                    {
                        return taskService.TakeTaskAuditPass(uid, taskAuditPassInput.TaskTakeID);
                    });
                    return r;
                }
                catch (PolicyRetryException ex)
                {
                    Logger.LogException(ex, taskAuditPassInput);

                    throw new BizException("系统繁忙");
                }
            }
            else
            {
                try
                {
                    var r = PolicyUtil.WaitAndRetry<bool>(new int[] { 1, 2, 2 }, () =>
                      {
                          return taskService.TakeTaskAuditNoPass(uid, taskAuditPassInput.TaskTakeID, taskAuditPassInput.AuditInfo);
                      });
                    return r;
                }
                catch (PolicyRetryException ex)
                {
                    Logger.LogException(ex, taskAuditPassInput);

                    throw new BizException("系统繁忙");
                }

            }

        }
        public bool DelTaskByUser(int uid, int taskID)
        {
            var task = taskRepository.GetByKey(taskID);
            if (task.UserID != uid) throw new BizException("任务不是该用户所有");
            if (task.Status != TaskStatus.待发布) throw new BizException($"'{task.Status.ToString()}'的任务无法删除！");
            task.IsDelete = true;

            var desc = $"总数量:{task.TotalCount} 剩余数量:{task.RemainCount} 已完成:{task.BeFinishCount}";
            taskService.TaskLog(task.ID, uid, TaskLogType.用户删除任务, null, desc);

            efUnitOfWork.Commit();

            return true;
        }

        public dynamic TaskAdditional(int uid, int taskID, int num)
        {
            var task = taskRepository.GetByKey(taskID);
            if (task.UserID != uid) throw new BizException("任务不是该用户所有！");

            var statusArr = new[] { TaskStatus.进行中, TaskStatus.任务完成, TaskStatus.任务关闭 };
            if (task.Status == TaskStatus.任务待完成) throw new BizException($"任务正在执行完成流程不能追加数量，请稍后重试！");
            if (!statusArr.Contains(task.Status)) throw new BizException($"任务{task.Status.ToString()}不能追加数量！");

            var c_order = task.TaskAudits.Max(i => i.Order) + 1;
            TaskAudit taskAudit = new TaskAudit();

            taskAudit.AuditStatus = TaskAuditStatus.审核通过;
            taskAudit.IsAdd = true;
            taskAudit.IsFinishAll = task.IsFinishAll;
            taskAudit.IsPay = task.IsFinishAll;
            taskAudit.LimitAudit = task.LimitAudit;
            taskAudit.LimitTime = task.LimitTime;
            taskAudit.Order = c_order;
            taskAudit.Price = task.Price;
            taskAudit.IsPay = false;
            taskAudit.PayMoney = taskAudit.TotalMoney = num * task.Price;
            taskAudit.CT = taskAudit.UT = DateTime.Now;
            taskAudit.Count = num;

            task.TaskAudits.Add(taskAudit);

            efUnitOfWork.Commit();

            return new { TaskID = task.ID, TaskAuditID = task.TaskAudits.FirstOrDefault(i => i.Order == c_order)?.ID };
        }



        public bool SetTaskStatus(int uid, int taskID, TaskStatus taskStatus)
        {
            var statusarr = new[] { TaskStatus.任务关闭, TaskStatus.暂停, TaskStatus.任务待关闭, TaskStatus.任务待完成, TaskStatus.任务恢复 };
            if (!statusarr.Contains(taskStatus)) throw new BizException("状态参数不正确！");

            var task = taskRepository.GetByKey(taskID);
            if (task.UserID != uid) throw new BizException("任务不是该用户所有！");

            switch (taskStatus)
            {
                case TaskStatus.暂停:
                    {
                        if (task.Status != TaskStatus.进行中) throw new BizException("操作失败，任务必须是进行中的状态！");
                        task.Status = taskStatus;
                    }
                    break;
                case TaskStatus.任务恢复:
                    {
                        if (task.Status != TaskStatus.暂停) throw new BizException("操作失败，任务必须是暂停的状态！");
                        task.Status = TaskStatus.进行中;
                        taskService.Restore(task.ID);
                    }
                    break;
                case TaskStatus.任务待关闭:
                case TaskStatus.任务关闭:
                    {
                        if (!(task.Status == TaskStatus.进行中 || task.Status == TaskStatus.暂停)) throw new BizException("操作失败，任务必须是进行中的状态！");
                        //task.Status = taskStatus;
                        taskService.DoTaskClose(task, TaskStatus.任务关闭);
                    }
                    break;
                default:
                    throw new BizException("操作失败，状态参数不正确！");
            }

            taskDetailsCache.RemoveCache(taskID);

            efUnitOfWork.Commit();

            return true;
        }
    }
}
